import numpy as np
from openpyxl import Workbook,load_workbook
import pickle
import random
import copy
import datetime
save_data_dir=r"D:\Personal\Desktop\beifen"
wb = load_workbook('D:/Personal/Desktop/InputData.xlsx', read_only=True)
ws=wb['Pucks']
wc=wb['Gates']
we=wb['Tickets']

class plane():
    def __init__(self,Fa,Fd,P,A,D,no,name,Dd_d,Dd_hb,Cf_d,Cf_hb):
        self.Fa = Fa  #到达类型
        self.Fd= Fd #出发类型
        self.P = P
        self.A = A  #到达时间
        self.D = D  #出发时间
        self.No=no
        self.name=name
        self.Dd_d=Dd_d
        self.Dd_hb=Dd_hb
        self.Cf_d=Cf_d
        self.Cf_hb=Cf_hb
        self.Cf_list=[]
        self.Dd_list=[]
class port():
    def __init__(self,Ha,Hd,G,no,name,port_l,port_aer):
        self.Ha = Ha
        self.Hd= Hd
        self.G = G
        self.No=no
        self.S_pl=[]
        self.name=name
        self.port_l=port_l
        self.port_aer=port_aer
class Tickets():
    def __init__(self,Dd_hb,Cf_hb,Dd_day,Cf_day,P_num,P_list):
        self.Dd_hb = Dd_hb #到达航班
        self.Cf_hb= Cf_hb #出发航班
        self.Dd_day = Dd_day
        self.Cf_day = Cf_day
        self.P_num=P_num
        self.P_list=P_list
        self.T_ftrans=None
        self.T_flow=None
        self.Cf_t = None  #航班的出发时间
        self.Dd_t = None   #到达时间
        self.Cf_l = None  #航班的出发类型
        self.Dd_l = None   #到达类型
        self.Dd_port = None #到达登机口终端厅
        self.Cf_port = None #出发登机口终端厅
        self.Cf_port_aer = None #出发登机口区域类型  
        self.Dd_port_aer = None #到达登机口区域类型
        self.T_tx = None #捷运时间  注意要*次数再 /5
        self.T_w = None #行走时间  注意要 /5
        self.n=None
    def flow(self,Cf_l,Dd_l,Dd_port,Cf_port):  #出发类型、航站楼（终端厅） 到达类型、到达航站楼
        if Cf_l==1: #出发国内D
            if Dd_l==1: #到达国内D
                if Cf_port=="T": #出发T
                    if Dd_port=="T": #到达T
                        return 3 ,0
                    else: #到达S
                        return 4 ,8/5
                else: #出发S
                     if Dd_port=="T": #到达T
                        return 4 ,8/5
                     else: #到达S
                        return 3 ,0
            else: #到达国际I
                if Cf_port=="T": #出发T
                    if Dd_port=="T": #到达T
                        return 7 ,0
                    else: #到达S
                        return 8 ,8/5
                else: #出发S
                     if Dd_port=="T": #到达T
                        return 8 ,8/5
                     else: #到达S
                        return 9 ,16/5

        else: #出发国际I
            if Dd_l==1: #到达国内D
                if Cf_port=="T": #出发T
                    if Dd_port=="T": #到达T
                        return 7 ,0
                    else: #到达S
                        return 8 ,8/5
                else: #出发S
                     if Dd_port=="T": #到达T
                        return 8 ,8/5
                     else: #到达S
                        return 7 ,0
            else: #到达国际I
                if Cf_port=="T": #出发T
                    if Dd_port=="T": #到达T
                        return 4 ,0
                    else: #到达S
                        return 6 ,8/5
                else: #出发S
                     if Dd_port=="T": #到达T
                        return 6 ,8/5
                     else: #到达S
                        return 4 ,0
    def out2(self):
        if self.Cf_t == None or self.Dd_t == None or self.Dd_port == None or self.Cf_port == None:
            self.T_flow=0
            self.T_ftrans=0
            return 0
        else:
            self.T_ftrans=self.Cf_t-self.Dd_t #航班连接时间 
            self.T_flow,self.T_tx=self.flow(self.Cf_l, self.Dd_l, self.Dd_port, self.Cf_port)               #最短流程时间
            if self.T_ftrans>=self.T_flow: # 换乘 成功
                return self.T_flow*self.P_num
            else: #换乘失败
                self.T_flow=72
                return 72

    def out3(self):
        i=0
        j=0
        if self.Dd_port=="T":
            if self.Dd_port_aer=="North":
                i=1
            elif self.Dd_port_aer=="Center":
                i=2
            elif self.Dd_port_aer=="South":
                i=3
        elif self.Dd_port=="S" :
            if self.Dd_port_aer=="North":
                i=4
            elif self.Dd_port_aer=="Center":
                i=5
            elif self.Dd_port_aer=="South":
                i=6
            elif self.Dd_port_aer=="East":
                i=7
        if self.Cf_port=="T":
            if self.Cf_port_aer=="North":
                j=1
            elif self.Cf_port_aer=="Center":
                j=2
            elif self.Cf_port_aer=="South":
                j=3
        elif self.Cf_port=="S" :
            if self.Cf_port_aer=="North":
                j=4
            elif self.Cf_port_aer=="Center":
                j=5
            elif self.Cf_port_aer=="South":
                j=6
            elif self.Cf_port_aer=="East":
                j=7
        a=[[10,15,20,25,20,25,25],
           [15,10,15,20,15,20,20],
           [20,15,10,25,20,25,25],
           [25,20,25,10,15,20,20],
           [20,15,20,15,10,15,15],
           [25,20,25,20,15,10,20],
           [25,20,25,20,15,20,10],]
            


                
        self.T_w=a[i-1][j-1]/5
        return self.T_w
    def n_out(self):
        self.out2()
        self.out3()
        if self.T_w==None or self.T_tx==None or self.T_flow==None or self.T_ftrans==None or self.T_ftrans==0:
            return 0
        else:        
            self.n=(self.T_w+self.T_tx+self.T_flow)/self.T_ftrans
            return self.n*self.P_num

def save_pickle_data(save_data_dir, save_data, dataname):
    # 保存数据集
    with open(save_data_dir + "/" + dataname + ".pickle", "wb") as handle:
        # pickle.dump(save_data, handle)
        pickle.dump(save_data, handle, protocol=pickle.HIGHEST_PROTOCOL)
    handle.close()
 
 
def read_pickle_data(save_data_dir, dataname):
    with open(save_data_dir + "/" + dataname + ".pickle", 'rb') as handle:
        read_data = pickle.load(handle)
    handle.close()
    return read_data

def S_T(plane,port):
    if plane.Fa*port.Ha>=0 and plane.Fd*port.Hd>=0 and plane.P-port.G==0:
        return True
    else:
        return False

def F(St,port):
    f1=len(St)
    f2=0
    for port_ in port:
        f2+=len(port_.S_pl)/(len(port_.S_pl)+0.00001)
    return f1*70+int(f2)

def Sol(planes,ports):
    PLANES=copy.deepcopy(planes)
    PLANES1=copy.deepcopy(planes)
    PORTS1=copy.deepcopy(ports)
    PORTS=copy.deepcopy(ports)
    TICKETS1=copy.deepcopy(tickets)
    TICKETS=copy.deepcopy(tickets)
    St=[]
    St1=[]
    de=0
    ST__=[]

    for count in range(len(planes)): 
        print(count)
        PORTS1.clear()
        PORTS.clear()
        PORTS1=copy.deepcopy(ports)
        PORTS=copy.deepcopy(ports)
        St.clear()
        St1.clear()
        for plane_ in PLANES:
            for port_ in PORTS:
               bool1=False
               if S_T(plane_,port_): #约束条件满足
                   if len(port_.S_pl)==0:
                       port_.S_pl.append(plane_)
                       bool1=True
                       break
                   elif plane_.A-port_.S_pl[-1].D-9>=0:
                        port_.S_pl.append(plane_)
                        bool1=True
                        break               
            if bool1:
                pass
            else:
                St.append(plane_)
        for port_ in PORTS:
            for pla in port_.S_pl:
               for tic in TICKETS:
                    if pla.Cf_hb==tic.Cf_hb and pla.Cf_d==tic.Cf_day:
                        tic.Cf_t=pla.D
                        tic.Cf_l=pla.Fd
                        tic.Cf_port=port_.port_l
                        tic.Cf_port_aer=port_.port_aer
                    if pla.Dd_hb==tic.Dd_hb and pla.Dd_d==tic.Dd_day:
                        tic.Dd_t=pla.A
                        tic.Dd_l=pla.Fa
                        tic.Dd_port=port_.port_l
                        tic.Dd_port_aer=port_.port_aer
        f3_=0
            
        for tic in TICKETS:
            
            f3_+=tic.out2()

            #tic.out2()
            #tic.out3()
            #f3_+=tic.n_out()


            

        St1.append(planes[count-de])
        del PLANES1[count-de]
    
        for plane_ in PLANES1:
            for port_ in PORTS1:
                bool1=False
                if S_T(plane_,port_): #约束条件满足
                    if len(port_.S_pl)==0:
                        port_.S_pl.append(plane_)
                        bool1=True
                        break
                    elif plane_.A-port_.S_pl[-1].D-9>=0:
                        port_.S_pl.append(plane_)
                        bool1=True
                        break
            if bool1:
                pass
            else:
                St1.append(plane_)

        for port_ in PORTS1:
            for pla in port_.S_pl:
               for tic in TICKETS1:
                    if pla.Cf_hb==tic.Cf_hb and pla.Cf_d==tic.Cf_day:
                        tic.Cf_t=pla.D
                        tic.Cf_l=pla.Fd
                        tic.Cf_port=port_.port_l
                        tic.Cf_port_aer=port_.port_aer
                    if pla.Dd_hb==tic.Dd_hb and pla.Dd_d==tic.Dd_day:
                        tic.Dd_t=pla.A
                        tic.Dd_l=pla.Fa
                        tic.Dd_port=port_.port_l
                        tic.Dd_port_aer=port_.port_aer
        f3_1=0
        for tic in TICKETS1:
            f3_1+=tic.out2()
            #tic.out2()
            #tic.out3()
            #f3_1+=tic.n_out()
            
        if F(ST__+St,PORTS)+f3_>=F(ST__+St1,PORTS1)+f3_1:
            value=F(St1+ST__,PORTS1)+f3_1
            PLANES=copy.deepcopy(PLANES1)
            TICKETS_resolt=copy.deepcopy(TICKETS1)
            ports_linshi=copy.deepcopy(PORTS1)
            ST_linshi=copy.deepcopy(St1)
            ST__.append(planes[count-de])
            de+=1
        
        else:
            value=F(St+ST__,PORTS)+f3_
            PLANES1=copy.deepcopy(PLANES)
            TICKETS_resolt=copy.deepcopy(TICKETS)
            ports_linshi=copy.deepcopy(PORTS)
            ST_linshi=copy.deepcopy(St)
               
    PORTS=copy.deepcopy(ports_linshi)
    ST=ST__+ST_linshi
    return value,PORTS,ST,TICKETS_resolt

##写入数据
planes=read_pickle_data(save_data_dir,"planes_2")
ports=read_pickle_data(save_data_dir,"ports_2") #飞机和停机口按属性建类 飞机0-302  303个 。停机口0-68  69个
tickets=read_pickle_data(save_data_dir,"tickets_2")

#循环计算
value0=100000
T=0 #循环次数
value0,PORTS_resalt,ST_resalt,TICKETS_resolt=read_pickle_data(save_data_dir,"登机口结果2")
print("读取历史最优值为：",value0)


for T_ in range(T):
    print("第",T_+1,"/",T,"次计算")
    random.shuffle(ports)
    #排序 str.remove(2)
    value,PORTS,ST,TICKETS_resolt=Sol(planes,ports)
    if value<value0:
        print("最优值更新为",value)
        value0=value
        PORTS_resalt=copy.deepcopy(PORTS)
        ST_resalt=copy.deepcopy(ST)
        result_save=copy.deepcopy([value0,PORTS_resalt,ST_resalt,TICKETS_resolt])
        save_pickle_data(save_data_dir,result_save,"登机口结果2")
    PORTS.clear()
    ST.clear()
i1=0
i2=0
i3=0
for p in PORTS_resalt:
    sum=0
    print("登机口",p.No,":",end='')
    if len(p.S_pl)!=0:
        i1+=1
        for pl in p.S_pl:
            print("飞机",pl.No, ";",end='')
            i2+=1

            if pl.D>288*2:
                D=288*2
            else:
                D=pl.D
            if pl.A<288:
                A=288
            else:
                A=pl.A
            sum+=D-A+9
    if (sum-9)/288>0.8:
        i3+=1
    print((sum-9)/288)
print(i3)

print("临时停机口",":",end='')
for s in ST_resalt:
    print("飞机",s.No, ";",end='')
print("\n已使用登机口；",i1,"\n登机口飞机：",i2,"\n临时登机口飞机:",len(ST_resalt),"\n优化值：",value0)

i1=0
i2=0
i3=0  
sum=0
for pp in TICKETS_resolt:
    if pp.T_flow==72:
        i1+=1
    elif pp.T_flow==0:
        i2+=1
    else:
        i3+=1
    sum+=pp.T_flow
print("\n换乘失败；",i1,"\n未换乘：",i2,"\n成功换乘:",i3)
        
